package stattracker;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

// This class will provide the interface to the remote database

public class Database 
{
	//TODO Remove sensitive information before each check in.
	private static final String dbURL = "jdbc:mysql://<url>:<port>/<dbname>";
	private static final String dbUser = "<dbusername>";
	private static final String dbPassword = "<dbpassword>";
	
	
	private static final String insertH3Save = "CALL insertH3SaveFile(?, ?, ?)";
	
	public static final int INVALID_ID = -1;
	
	private static Database instance;
	private Connection conn;
	private Statement stmt;
	
	private Database() throws DatabaseInaccessibleException
	{
		boolean failed = false;
		try {
			Class.forName("com.mysql.jdbc.Driver");
			conn = DriverManager.getConnection(dbURL, dbUser, dbPassword);
		}
		catch(SQLException e)
		{
			e.printStackTrace();
			failed = true;
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			failed = true;
		}
		finally
		{
			if(failed)
				throw new DatabaseInaccessibleException();
		}
	}
	
	public boolean isConnected()
	{
		if(instance == null)
			return false;
		if(conn == null)
			return false;
		
		try {
			if(conn.isClosed())
				return false;
		} catch (SQLException e) {
			e.printStackTrace();
			return false;
		}
		
		return true;
	}
	
	public static Database getInstance() throws DatabaseInaccessibleException
	{
		if(instance == null)
			instance = new Database();
		return instance;
	}
	
	public ResultSet query(String query) throws SQLException
	{
		stmt = conn.createStatement();
		return stmt.executeQuery(query);
	}
	
	public int getGamertagId(String gt)
	{
		try
		{
			ResultSet rs = query(String.format("CALL getGamertagID('%s')", gt));
			if(rs.next())
			{
				return rs.getInt(1);
			}
			else
			{
				new ErrorMessage("Gamertag Doesn't Exist in the Database");
			}
		}
		catch(SQLException e){
			e.printStackTrace();
		}
		return INVALID_ID;
	}
	
	public boolean getHalo3SaveFile(int id)
	{
		try {
			ResultSet rs = query(String.format("CALL getH3SaveFile(%d)",id));
			FileOutputStream outStream = new FileOutputStream(new File("temp.halo3"));
			rs.next();
			InputStream is = rs.getBlob(1).getBinaryStream();
			
			byte[] buffer = new byte[4096];
			int ch = 0;
			while((ch = is.read(buffer)) != -1)
			{
				outStream.write(buffer, 0, ch);
			}
			outStream.close();
			return true;
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return false;
	}
	
	public void insertHalo3SaveFile(int id, String file)
	{
		if(!hasNewerSaveFile(file.replace(".halo3", "")))
		{
			PreparedStatement ps;
			FileInputStream fileStream;
			try
			{
				conn.setAutoCommit(false);
				File H3Save = new File(file);
				fileStream = new FileInputStream(H3Save);
				ps = conn.prepareStatement(insertH3Save);
				ps.setInt(1, id);
				ps.setBinaryStream(2, fileStream, H3Save.length());
				ps.setInt(3, (int)H3Save.length());
				ps.executeUpdate();
				conn.commit();
				ps.close();
				fileStream.close();
			}
			catch(SQLException e){e.printStackTrace();}
			catch(FileNotFoundException e){e.printStackTrace();} 
			catch(IOException e) {e.printStackTrace();}
			finally
			{
				try {
					conn.setAutoCommit(true);
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
		}
		else
		{
			System.out.println("Skipped.");
		}
		//TODO more meaningful catch blocks
	}

	public boolean hasNewerSaveFile(String gt) 
	{
		String fileLoc = gt + ".halo3";
		int id = getGamertagId(gt);
		if(id != INVALID_ID)
		{
			try {
				ResultSet rs = query(String.format("CALL getH3SaveFileSize(%d)", id));
				if(rs.next())
				{
					if(new File(fileLoc).length() < rs.getInt(1))
						return true;
				}
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		
		return false;
	}
	
}
